<!-- templates/mqtt_monitor.html -->
<!DOCTYPE html>
<html>
<head>
    <title>MQTT Monitor</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
    <style>
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }

        body {
            font-family: Arial, sans-serif;
            background-color: #f5f5f5;
            font-size: 14px;
        }

        .container {
            max-width: 100%;
            margin: 0;
            padding: 10px;
        }

        .header {
            background: #007bff;
            color: white;
            padding: 15px;
            margin: -10px -10px 15px -10px;
            text-align: center;
            font-size: 18px;
            font-weight: bold;
        }

        .status {
            padding: 10px;
            margin: 10px 0;
            border-radius: 8px;
            text-align: center;
            font-weight: bold;
        }
        .connected { background-color: #d4edda; color: #155724; }
        .disconnected { background-color: #f8d7da; color: #721c24; }

        .control-grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 10px;
            margin-bottom: 15px;
        }

        .control-panel {
            background: white;
            padding: 15px;
            border-radius: 12px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
        }

        .control-panel h3 {
            margin-bottom: 12px;
            color: #333;
            font-size: 16px;
            text-align: center;
        }

        .btn-group {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(60px, 1fr));
            gap: 8px;
        }

        .btn {
            padding: 12px 8px;
            border: none;
            border-radius: 8px;
            color: white;
            font-size: 12px;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.2s;
            min-height: 44px;
        }

        .btn:active {
            transform: scale(0.95);
        }

        .btn-primary { background: #007bff; }
        .btn-success { background: #28a745; }
        .btn-danger { background: #dc3545; }
        .btn-warning { background: #ffc107; color: #212529; }

        .direction-grid {
            display: grid;
            grid-template-columns: 1fr 1fr 1fr;
            grid-template-rows: 1fr 1fr 1fr;
            gap: 5px;
            max-width: 200px;
            margin: 0 auto;
        }

        .direction-grid .btn {
            aspect-ratio: 1;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            font-size: 10px;
            padding: 8px 4px;
        }

        .direction-grid div:empty {
            /* 空位样式 */
        }

        .joystick-container {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 10px;
        }

        #joystick-area {
            position: relative;
            width: 100px;
            height: 100px;
            background: #eee;
            border-radius: 50px;
            border: 3px solid #ddd;
        }

        #joystick {
            position: absolute;
            left: 30px;
            top: 30px;
            width: 40px;
            height: 40px;
            background: #007bff;
            border-radius: 20px;
            touch-action: none;
            cursor: pointer;
        }

        .input-group {
            display: flex;
            gap: 8px;
            margin-bottom: 10px;
        }

        .input-group input {
            flex: 1;
            padding: 12px;
            border: 1px solid #ddd;
            border-radius: 6px;
            font-size: 14px;
        }

        .input-group button {
            min-width: 80px;
        }

        .slider-container {
            margin: 10px 0;
        }

        .slider-container input[type="range"] {
            width: 100%;
            height: 8px;
            border-radius: 4px;
            background: #ddd;
            outline: none;
            -webkit-appearance: none;
        }

        .slider-container input[type="range"]::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 20px;
            height: 20px;
            border-radius: 50%;
            background: #007bff;
            cursor: pointer;
        }

        .status-display {
            text-align: center;
            margin: 10px 0;
            padding: 8px;
            background: #f8f9fa;
            border-radius: 6px;
            font-weight: bold;
        }

        .full-width {
            grid-column: 1 / -1;
        }

        .messages-section {
            background: white;
            border-radius: 12px;
            padding: 15px;
            margin-top: 15px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
        }

        .message {
            border: 1px solid #eee;
            padding: 8px;
            margin: 5px 0;
            border-radius: 6px;
            font-size: 12px;
        }

        .message-topic {
            font-weight: bold;
            color: #007bff;
            margin-bottom: 4px;
        }

        .message-payload {
            margin: 4px 0;
        }

        .message-meta {
            font-size: 10px;
            color: #666;
        }

        #messages {
            max-height: 300px;
            overflow-y: auto;
        }

        .publish-section {
            background: white;
            border-radius: 12px;
            padding: 15px;
            margin-bottom: 15px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
        }

        /* 移动端优化 */
        @media (max-width: 768px) {
            .container { padding: 5px; }
            .control-grid { grid-template-columns: 1fr; }
            .btn { font-size: 14px; }
            .header { font-size: 16px; }
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            🔍 MQTT 小车控制台
        </div>

        <div id="status" class="status disconnected">
            ❌ 未连接
        </div>

        <!-- 控制面板网格 -->
        <div class="control-grid">
            <!-- 方向控制 -->
            <div class="control-panel">
                <h3>🕹️ 方向控制</h3>
                <div class="direction-grid">
                    <div></div> <!-- 空位 -->
                    <button class="btn btn-primary" onclick="sendControl('1')">⬆️<br>前进</button>
                    <div></div> <!-- 空位 -->

                    <button class="btn btn-primary" onclick="sendControl('3')">⬅️<br>左转</button>
                    <button class="btn btn-danger" onclick="sendControl('5')">⏹️<br>停止</button>
                    <button class="btn btn-primary" onclick="sendControl('4')">➡️<br>右转</button>

                    <button class="btn btn-warning" onclick="sendControl('6')">↙️<br>左后</button>
                    <button class="btn btn-primary" onclick="sendControl('2')">⬇️<br>后退</button>
                    <button class="btn btn-warning" onclick="sendControl('7')">↘️<br>右后</button>
                </div>
                <div class="status-display">
                    <span id="currentCommand">小车状态: 未知</span>
                </div>
            </div>

            <!-- 虚拟摇杆 -->
            <div class="control-panel">
                <h3>🎮 虚拟摇杆</h3>
                <div class="joystick-container">
                    <div id="joystick-area">
                        <div id="joystick"></div>
                    </div>
                    <div style="font-size: 10px; color: #666; text-align: center;">
                        拖动摇杆控制<br>7个方向
                    </div>
                </div>
            </div>

            <!-- 状态切换 -->
            <div class="control-panel">
                <h3>🔄 运行状态</h3>
                <div class="btn-group">
                    <button class="btn btn-danger" onclick="sendStatus('0')">停止</button>
                    <button class="btn btn-success" onclick="sendStatus('1')">循迹</button>
                    <button class="btn btn-warning" onclick="sendStatus('2')">避障</button>
                    <button class="btn btn-primary" onclick="sendStatus('3')">遥控</button>
                </div>
                <div class="status-display">
                    <span id="currentStatus">当前状态: 未知</span>
                </div>
            </div>

            <!-- 模式控制 -->
            <div class="control-panel">
                <h3>🚗 调试模式</h3>
                <div class="input-group">
                    <input type="number" id="modeInput" placeholder="模式">
                    <button class="btn btn-primary" onclick="sendModeFromInput()">发送</button>
                </div>
                <div class="status-display">
                    <span id="currentMode">当前参数: 未知</span>
                </div>
            </div>

            <!-- 速度控制 -->
            <div class="control-panel full-width">
                <h3>🚗 速度控制</h3>
                <div class="slider-container">
                    <input type="range" id="speedRange" min="0" max="100" value="0"
                           oninput="updateSpeedLabel(this.value)"
                           onchange="sendSpeed(this.value)">
                    <div style="display: flex; justify-content: space-between; margin-top: 5px;">
                        <span>0</span>
                        <span id="speedLabel" style="font-weight: bold; color: #007bff;">0</span>
                        <span>100</span>
                    </div>
                </div>
                <div class="status-display">
                    <span id="currentSpeedDisplay">当前速度: 未知</span>
                </div>
            </div>
        </div>

        <!-- 消息发布 -->
        <div class="publish-section">
            <h3>📤 发送消息</h3>
            <div class="input-group">
                <input type="text" id="topic" placeholder="主题" style="flex: 1;">
                <input type="text" id="message" placeholder="消息" style="flex: 2;">
                <button class="btn btn-primary" onclick="publishMessage()">发送</button>
            </div>
        </div>

        <!-- 消息历史 -->
        <div class="messages-section">
            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
                <h3>📨 消息记录 <span id="message-count">(0)</span></h3>
                <button class="btn btn-danger" onclick="clearMessages()">清空</button>
            </div>
            <div id="messages"></div>
        </div>
    </div>

    <script>
        const socket = io();
        let messageCount = 0;

        socket.on('mqtt_status', function(data) {
            const statusDiv = document.getElementById('status');
            if (data.status === 'connected') {
                statusDiv.className = 'status connected';
                statusDiv.innerHTML = '✅ 已连接到 MQTT';
            } else {
                statusDiv.className = 'status disconnected';
                statusDiv.innerHTML = '❌ MQTT 连接断开';
            }
        });

        socket.on('new_message', function(data) {
            displayMessage(data);

            // 处理速度消息
            if (data.topic === 'speed') {
                let val = parseInt(data.payload);
                if (!isNaN(val)) {
                    document.getElementById('speedRange').value = val;
                    updateSpeedLabel(val);
                }
            }

            // 处理当前速度消息
            if (data.topic === 'current_speed') {
                const currentSpeedDisplay = document.getElementById('currentSpeedDisplay');
                currentSpeedDisplay.textContent = `当前速度: ${data.payload}`;
            }

            // 处理当前状态消息
            if (data.topic === 'current_status') {
                const statusDisplay = document.getElementById('currentStatus');
                const statusMap = {
                    '0': '停止模式',
                    '1': '循迹模式',
                    '2': '避障模式',
                    '3': '遥控模式'
                };
                const statusText = statusMap[data.payload] || `状态 ${data.payload}`;
                statusDisplay.textContent = `当前状态: ${statusText}`;
            }

            // 处理name主题消息，直接显示小车当前指令状态
            if (data.topic === 'name') {
                const commandDisplay = document.getElementById('currentCommand');
                const commandMap = {
                    '1': '前进',
                    '2': '后退',
                    '3': '左转',
                    '4': '右转',
                    '5': '停止',
                    '6': '向后左转',
                    '7': '向后右转'
                };
                const commandText = commandMap[data.payload] || `指令 ${data.payload}`;
                commandDisplay.textContent = `小车状态: ${commandText}`;
            }

            // 处理模式消息
            if (data.topic === 'mode') {
                const modeDisplay = document.getElementById('currentMode');
                modeDisplay.textContent = `当前模式: ${data.payload}`;
            }

            // 处理状态消息
            if (data.topic === 'status') {
                const statusDisplay = document.getElementById('currentStatus');
                const statusMap = {
                    '0': '停止模式',
                    '1': '循迹模式',
                    '2': '避障模式',
                    '3': '遥控模式'
                };
                const statusText = statusMap[data.payload] || `状态 ${data.payload}`;
                statusDisplay.textContent = `当前状态: ${statusText}`;
            }
        });

        function displayMessage(data) {
            const messagesDiv = document.getElementById('messages');
            const messageDiv = document.createElement('div');
            messageDiv.className = 'message';

            const timestamp = new Date(data.timestamp).toLocaleTimeString();

            messageDiv.innerHTML = `
                <div class="message-topic">📍 ${data.topic}</div>
                <div class="message-payload">📝 ${data.payload}</div>
                <div class="message-meta">
                    🕒 ${timestamp} | QoS: ${data.qos}
                </div>
            `;

            messagesDiv.insertBefore(messageDiv, messagesDiv.firstChild);

            messageCount++;
            document.getElementById('message-count').textContent = `(${messageCount})`;
        }

        function publishMessage() {
            const topic = document.getElementById('topic').value;
            const message = document.getElementById('message').value;

            if (!topic || !message) {
                alert('请输入主题和消息');
                return;
            }

            fetch('/api/publish', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    topic: topic,
                    message: message
                })
            })
            .then(response => response.json())
            .then(data => {
                if (data.status === 'success') {
                    document.getElementById('message').value = '';
                    console.log('消息发送成功');
                } else {
                    alert('消息发送失败');
                }
            });
        }

        function sendControl(cmd) {
            fetch('/api/publish', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    topic: 'name',
                    message: cmd
                })
            })
            .then(response => response.json())
            .then(data => {
                if (data.status !== 'success') {
                    alert('控制命令发送失败');
                }
            });
        }

        function sendModeFromInput() {
            const modeValue = document.getElementById('modeInput').value.trim();
            if (!modeValue) {
                alert('请输入模式数字');
                return;
            }

            fetch('/api/publish', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    topic: 'mode',
                    message: modeValue
                })
            })
            .then(response => response.json())
            .then(data => {
                if (data.status === 'success') {
                    console.log('模式发送成功:', modeValue);
                    document.getElementById('modeInput').value = '';
                } else {
                    alert('模式发送失败');
                }
            });
        }

        function sendStatus(statusValue) {
            fetch('/api/publish', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    topic: 'status',
                    message: statusValue
                })
            })
            .then(response => response.json())
            .then(data => {
                if (data.status === 'success') {
                    console.log('状态发送成功:', statusValue);
                } else {
                    alert('状态发送失败');
                }
            });
        }

        function updateSpeedLabel(val) {
            document.getElementById('speedLabel').textContent = val;
        }

        function sendSpeed(val) {
            fetch('/api/publish', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    topic: 'speed',
                    message: val
                })
            })
            .then(response => response.json())
            .then(data => {
                if (data.status !== 'success') {
                    alert('速度设置失败');
                }
            });
        }

        function clearMessages() {
            document.getElementById('messages').innerHTML = '';
            messageCount = 0;
            document.getElementById('message-count').textContent = '(0)';
        }

        // 支持回车键发送模式
        document.addEventListener('DOMContentLoaded', function() {
            const modeInput = document.getElementById('modeInput');
            if (modeInput) {
                modeInput.addEventListener('keypress', function(e) {
                    if (e.key === 'Enter') {
                        sendModeFromInput();
                    }
                });
            }

            // 加载历史消息
            fetch('/api/messages')
                .then(response => response.json())
                .then(messages => {
                    messages.forEach(message => {
                        displayMessage(message);
                    });
                });
        });

        // 虚拟摇杆控制逻辑
        (function() {
            const area = document.getElementById('joystick-area');
            const stick = document.getElementById('joystick');
            const areaSize = 100; // 摇杆区域大小
            const stickSize = 40; // 摇杆大小
            const center = { x: areaSize/2, y: areaSize/2 }; // 真正的中心点
            const maxDist = (areaSize - stickSize) / 2; // 最大移动距离
            let dragging = false;
            let lastCmd = null;

            function setStick(x, y) {
                const dx = x - center.x;
                const dy = y - center.y;
                const dist = Math.sqrt(dx*dx + dy*dy);

                let nx = dx, ny = dy;
                if (dist > maxDist) {
                    nx = dx * maxDist / dist;
                    ny = dy * maxDist / dist;
                }

                // 计算摇杆左上角位置（摇杆中心 - 摇杆半径）
                const stickX = center.x + nx - stickSize/2;
                const stickY = center.y + ny - stickSize/2;

                stick.style.left = stickX + 'px';
                stick.style.top = stickY + 'px';
            }

            function resetStick() {
                // 重置到中心位置
                const centerX = center.x - stickSize/2;
                const centerY = center.y - stickSize/2;
                stick.style.left = centerX + 'px';
                stick.style.top = centerY + 'px';
            }

           function getDirection(x, y) {
    const dx = x - center.x;
    const dy = y - center.y;
    const dist = Math.sqrt(dx*dx + dy*dy);

    // 死区检测
    if (dist < 15) return '5'; // 停止

    // 计算角度
    const angle = Math.atan2(-dy, dx) * 180 / Math.PI;
    let normalizedAngle = angle >= 0 ? angle : angle + 360;

    // 8个方向，每个45度
    if (normalizedAngle >= 337.5 || normalizedAngle < 22.5) {
        return '4'; // 右 (0°)
    } else if (normalizedAngle >= 22.5 && normalizedAngle < 67.5) {
        return '1'; // 右上 -> 映射为前进
    } else if (normalizedAngle >= 67.5 && normalizedAngle < 112.5) {
        return '1'; // 上 (90°) - 前进
    } else if (normalizedAngle >= 112.5 && normalizedAngle < 157.5) {
        return '3'; // 左上 -> 映射为左转
    } else if (normalizedAngle >= 157.5 && normalizedAngle < 202.5) {
        return '3'; // 左 (180°) - 左转
    } else if (normalizedAngle >= 202.5 && normalizedAngle < 247.5) {
        return '6'; // 左下 (225°) - 左后
    } else if (normalizedAngle >= 247.5 && normalizedAngle < 292.5) {
        return '2'; // 下 (270°) - 后退
    } else if (normalizedAngle >= 292.5 && normalizedAngle < 337.5) {
        return '7'; // 右下 (315°) - 右后
    }

    return '5';
}
            // 确保DOM完全加载后再初始化摇杆位置
            function initJoystick() {
                // 等��元素完全渲染
                setTimeout(() => {
                    resetStick();
                    console.log('摇杆初始化完成');
                }, 100);
            }

            // 初始化摇杆位置
            initJoystick();

            function onStart(e) {
                dragging = true;
                document.body.style.userSelect = 'none';
                e.preventDefault();
            }

            function onMove(e) {
                if (!dragging) return;
                let clientX, clientY;
                if (e.touches) {
                    clientX = e.touches[0].clientX;
                    clientY = e.touches[0].clientY;
                } else {
                    clientX = e.clientX;
                    clientY = e.clientY;
                }
                const rect = area.getBoundingClientRect();
                const x = clientX - rect.left;
                const y = clientY - rect.top;
                setStick(x, y);
                const cmd = getDirection(x, y);
                if (cmd !== lastCmd) {
                    sendControl(cmd);
                    lastCmd = cmd;
                }
                e.preventDefault();
            }

            function onEnd(e) {
                dragging = false;
                document.body.style.userSelect = '';
                resetStick();
                if (lastCmd !== '5') {
                    sendControl('5');
                    lastCmd = '5';
                }
                e.preventDefault();
            }

            stick.addEventListener('mousedown', onStart);
            document.addEventListener('mousemove', onMove);
            document.addEventListener('mouseup', onEnd);
            stick.addEventListener('touchstart', onStart);
            document.addEventListener('touchmove', onMove, {passive: false});
            document.addEventListener('touchend', onEnd);

            // 窗口大小改变时重新居中摇杆
            window.addEventListener('resize', function() {
                setTimeout(resetStick, 100);
            });
        })();
    </script>
</body>
</html>

